/*
 * common.cpp
 *
 *  Created on: Sep 4, 2013
 *      Author: jason
 */

#include <utility>
#include <algorithm>
#include <iostream>
#include "../include/GlobalState.hpp"
#include "../include/Common.hpp"

GlobalState* GlobalState::m_pInstance = NULL;

int GlobalEventGroup::getEventProgress(std::string name)
{
	std::unordered_map<std::string, int>::iterator it = eventMap.find(name);
	if (it == eventMap.end()) {
		std::cout << "Cannot get progress of event " << name;
		std::cout << " because the event does not exist.\n";
		return 0;
	}
	return it->second;
}

void GlobalEventGroup::setEventProgress(std::string name, int p)
{
	std::unordered_map<std::string, int>::iterator it = eventMap.find(name);
	if (it == eventMap.end()) {
		eventMap.insert(std::make_pair(name,p));
	} else {
		it->second = p;
	}
}

void GlobalParty::addCharacter(OForce_Object::Character *character)
{
	vMembers.push_back(character);
}

void GlobalParty::removeCharacter(OForce_Object::Character *character)
{
	std::vector<OForce_Object::Character *>::iterator it;
	it = std::find(vMembers.begin(), vMembers.end(), character);
	if (it != vMembers.end()) {
		vMembers.erase(it);
	}
}

bool GlobalParty::isMember(OForce_Object::Character *character)
{
	std::vector<OForce_Object::Character *>::iterator it;
	it = std::find(vMembers.begin(), vMembers.end(), character);
	if (it != vMembers.end()) {
		return true;
	}
	return false;
}

GlobalState* GlobalState::Instance()
{
	if (m_pInstance == NULL) // only allow one instance
	    m_pInstance = new GlobalState;
	return m_pInstance;
}

void GlobalState::KillInstance()
{
	delete m_pInstance;
	m_pInstance = NULL;
}

GlobalState::GlobalState()
{
	playerGender = 1;
	playerName = "Brynhild";
	mGold = 100;
	// Load all global scripts
	if (itemScript.openFile("data/Scripts/Items.lua") == false) {
		std::cerr << "Error loading Items script\n";
	}
	else {
		itemScript.openTable("Items");
	}
//	if (weaponScript.openFile("data/Scripts/Weapons.lua") == false) {
//		std::cerr << "Error loading weapons script\n";
//	}
//	weaponScript.openTable("Weapons");
//	if (accessoryScript.openFile("data/Scripts/Accessories.lua") == false) {
//		std::cerr << "Error loading weapons script\n";
//	}
//	accessoryScript.openTable("Accessories");
	if (characterScript.openFile("data/Scripts/Characters.lua") == false) {
		std::cerr << "Error loading characters script\n";
	}
//	else {
//		std::cout << "Loading character script\n";
//		characterScript.openTable("Characters");
//	}
}

GlobalState::~GlobalState()
{
//	itemScript.closeTable();
	itemScript.closeFile();
//	characterScript.closeTable();
	characterScript.closeFile();
	resetGame();
}

void GlobalState::resetGame()
{
	for (std::unordered_map<std::string, GlobalEventGroup *>::iterator it = eventGroupMap.begin();
			it != eventGroupMap.end(); it++) {
		delete it->second;
	}
	eventGroupMap.clear();
}

void GlobalState::addCharacter(OForce_Object::Character *character)
{
	if (isPartyMember(character->getID())) {
		if (character->isActiveMember()) {
			character->setActiveMember(true);
			battleParty.addCharacter(character);
			return;
		}
		std::cerr << "Error: attempted to add a character to the party who was";
		std::cerr << " already a member.\n";
		return;
	}
	character->setActiveMember(true);
	battleParty.addCharacter(character);
	characterMap.insert(std::make_pair(character->getID(), character));
}

void GlobalState::removeFromParty(OForce_Object::Character *character)
{
	std::unordered_map<int, OForce_Object::Character *>::iterator it;
	it = characterMap.find(character->getID());
	if (it != characterMap.end()) {
		it->second->setActiveMember(false);
		if (battleParty.isMember(character)) {
			battleParty.removeCharacter(character);
		}
	}
}

bool GlobalState::doesEventGroupExist(std::string name)
{
	std::unordered_map<std::string, GlobalEventGroup *>::iterator it = eventGroupMap.find(name);
	if (it != eventGroupMap.end()) {
		return true;
	}
	return false;
}

bool GlobalState::doesEventExist(std::string groupName, std::string eventName)
{
	// Does group exist?
	std::unordered_map<std::string, GlobalEventGroup *>::iterator it = eventGroupMap.find(groupName);
	if (it == eventGroupMap.end()) {
		return false;
	}
	// does event exist in the group?
	std::unordered_map<std::string, int>::iterator eventIt = it->second->getEvents().find(eventName);
	if (eventIt == it->second->getEvents().end()) {
		return false;
	}
	return true;
}

void GlobalState::addEventGroup(std::string name)
{
	if (doesEventGroupExist(name)) {
		std::cerr << "Error: attempted to create a event group " << name;
		std::cerr << " when a group already existed with that name.\n";
		return;
	}
	GlobalEventGroup *evGrp = new GlobalEventGroup(name);
	eventGroupMap.insert(std::make_pair(name, evGrp));
}

int GlobalState::getEventValue(std::string groupName, std::string eventName) const
{
	GlobalEventGroup *evGrp;
	std::unordered_map<std::string, GlobalEventGroup *>::const_iterator it = eventGroupMap.find(groupName);
	if (it == eventGroupMap.end()) {
		return 0;
	} else {
		evGrp = it->second;
	}
	return evGrp->getEventProgress(eventName);
}

void GlobalState::setEventValue(std::string groupName, std::string eventName, int value)
{
	GlobalEventGroup *evGrp;
	std::unordered_map<std::string, GlobalEventGroup *>::const_iterator it = eventGroupMap.find(groupName);
	if (it == eventGroupMap.end()) {
		evGrp = new GlobalEventGroup(groupName);
		eventGroupMap.insert(std::make_pair(groupName, evGrp));
	} else {
		evGrp = it->second;
	}
	evGrp->setEventProgress(eventName, value);
}

bool GlobalState::addToPartyInventory(int itemID)
{
	std::vector<OForce_Object::Character *>::iterator it;
	for (it = battleParty.vMembers.begin();
			it != battleParty.vMembers.end(); it++) {
		if ((*it)->getNumItems() < 4) {
			break;
		}
	}
	if (it == battleParty.vMembers.end()) {
		std::cout << "inventory full\n";
		return false;
	} else {
		(*it)->addItem(itemID);
		return true;
	}
}
